package model;

import control.ControllerPrincipal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import vinciappli.CardId;
import vinciappli.ProvinceSubType;
import vinciappli.StaticParams;


public class GameBoard {

    private Set<Province> provinces = new HashSet<Province>();
    private List<CivilPlace> civilizations = new ArrayList<CivilPlace>();
    private Bag bag = new Bag();
    private Set<SeaArea> seaAreas = new HashSet<SeaArea>();
    /* Points given to each player at the beginning of the game */
    private int initialPts = StaticParams.INITIAL_PTS;
    /* Points needed to win the game */
    private int maxPts = StaticParams.MAX_PTS_3_PLAYERS;
    /* Zone which represents the edge of the gameboard, the place where all players have to start */
    private Zone gameBoardEdge = new Zone(StaticParams.GAMEBOARD_EDGE_ID);

    public void fillCivilizationPlaces()
    {
        while(civilizations.size() < StaticParams.NB_GAMEBOARD_PLACES_CIVILIZATION)
        {
            civilizations.add(new CivilPlace(new Civilization(bag.getRandomCard(), bag.getRandomCard())));
        }
    }

    /**
     * Put a fort on every province on the gameboard except mountain provinces
     */
    public void setPreviousForces()
    {
        for(Province p : provinces)
        {
            if(!p.getFieldType().equals(StaticParams.PROVINCE_FIELDTYPE_MOUNTAIN))
            {
                p.getTerritoryOccupation().put(StaticParams.PAWN_TYPE_FORT, 1);
            }
        }
    }
    
    /**
     * Find all provinces that could be conquered by a player at the beginning of his empire
     * <br>- Card "revolution" supported
     * @param p : Player who's playing
     * @return : Set of provinces
     */
    public Set<Province> getStartingProvinces(Player p)
    {
        Set<Province> startingProvinces = new HashSet<Province>();
        
        startingProvinces.addAll(gameBoardEdge.getNearbyProvinces());

        for(SeaArea sa : gameBoardEdge.getNearbySeaAreas())
        {
           startingProvinces.addAll(sa.getNearbyProvincesThroughSeas());
        }

        for(Province pr : startingProvinces)
        {
            if(pr.isAdjacent(p.getEmpire(true)))
            {
                // TODO Cas ou une province d'entrée est adjacente à l'empire en déclin d'un même joueur
            }
        }
        if(p.getEmpire(true) != null && p.getEmpire(false).getCivilization().isComposedOf(CardId.revolution))
        {
            return provinces;
        }
        return startingProvinces;
    }

    /**
     * Calculation of points won for a player thanks to his civilization cards
     * <br>- Card "specialisation" supported
     * @param p : Current player
     * @return : Total points from cards advantage
     */
    public int cardAdvantageCalculation(Player p)
    {
        int pts = 0;
        Empire activeEmpire = p.getEmpire(false);
        Card activeCard1 = activeEmpire.getCivilization().getCaracteristic1();
        Card activeCard2 = activeEmpire.getCivilization().getCaracteristic2();
        Empire depressedEmpire = p.getEmpire(true);
        Card depressedCard1 = depressedEmpire.getCivilization().getCaracteristic1();
        Card depressedCard2 = depressedEmpire.getCivilization().getCaracteristic2();
       
        pts += getBonusPtsFromCard(activeCard1, activeEmpire);
        pts += getBonusPtsFromCard(activeCard2, activeEmpire);
        if(activeEmpire.getCivilization().isComposedOf(CardId.specialisation))
        {
            pts = pts*2;
        }

        if(depressedCard1 != null)
        {
            pts += getBonusPtsFromCard(depressedCard1, depressedEmpire);
        }
        if(depressedCard2 != null)
        {
            pts += getBonusPtsFromCard(depressedCard2, depressedEmpire);
        }

        return pts;
    }

    /**
     * Calculation of points of specific yellow cards related to provinces types
     * @param c : Card analyzed
     * @param e : Empire analyzed
     * @return : Total amount of points won from yellow cards advantage
     */
    private int getBonusPtsFromCard(Card c, Empire e)
    {
        int pts = 0;
        
        switch(c.getType())
        {
            case agriculture :
            case agricultureDec :
                pts += e.getNbProvinceBySubType(ProvinceSubType.FARM);
            break;
 
            case elevage :
            case elevageDec :
                pts += e.getNbProvinceBySubType(ProvinceSubType.FARMING);
            break;

            case ports :
            case portsDec :
                pts += e.getNbProvinceBySubType(ProvinceSubType.PORT);
            break;

            case mines :
            case minesDec :
                pts += e.getNbProvinceBySubType(ProvinceSubType.MINING) * 2;
            break;

            case monnaie :
                pts += e.getListProvinces().size();
            break;

            case esclavage :
                pts += ControllerPrincipal.getINSTANCE().getControllerGameBoard().getAssaultBonusPts();
            break;

            case montagnard :
                pts += e.getNbProvinceByType(StaticParams.PROVINCE_FIELDTYPE_MOUNTAIN);
            break;
                
        }
        return pts;
    }

    public Zone getZoneByNum(int num)
    {
        for(Zone z : provinces)
        {
            if(z.getNum() == num)
            {
                return z;
            }
        }
        for(Zone z : seaAreas)
        {
            if(z.getNum() == num)
            {
                return z;
            }
        }
        return null;
    }

    /***************************** GETTERS & SETTERS **************************/

    public List<CivilPlace> getCivilizations () {
        return civilizations;
    }

    public int getInitialPts () {
        return initialPts;
    }

    public void setInitialPts (int val) {
        this.initialPts = val;
    }

    public int getMaxPts () {
        return maxPts;
    }

    public void setMaxPts (int val) {
        this.maxPts = val;
    }

    public Set<Province> getProvinces () {
        return provinces;
    }

    public void setProvinces (Set<Province> val) {
        this.provinces = val;
    }

    public Set<SeaArea> getSeaAreas () {
        return seaAreas;
    }

    public void setSeaAreas (Set<SeaArea> val) {
        this.seaAreas = val;
    }

    public Bag getBag() {
        return bag;
    }

    public Zone getGameBoardEdge() {
        return gameBoardEdge;
    }

    
}

